import { invertColor } from './color_inverter';

interface InlineStyles {
  [key: string]: string;
}

function injectColor(
  target: InlineStyles,
  styleObj: CSSStyleDeclaration,
  element: HTMLElement
) {
  let leafElement = true;
  const nodes = element.childNodes;
  for (let i = 0, l = nodes.length; i < l; ++i) {
    if (nodes[i].nodeType === Node.ELEMENT_NODE) {
      leafElement = false;
      break;
    }
  }
  if (leafElement) {
    const color = styleObj.getPropertyValue('color');
    let it: HTMLElement | null = element;
    while (it) {
      const bgColor = getComputedStyle(it).getPropertyValue('background-color');
      const alpha = bgColor
        .slice(bgColor.indexOf('(') + 1, bgColor.indexOf(')'))
        .split(',')[3];
      if (alpha && parseFloat(alpha) < 0.1) {
        it = it.parentElement;
        continue;
      }

      if (color === bgColor) {
        try {
          target['color'] = invertColor(color);
        } catch (e) {
          console.log(e);
        }
      }
      break;
    }
  }
}

function injectColor2(
  target: InlineStyles,
  styleObj: CSSStyleDeclaration,
  element: HTMLElement
) {
  let leafElement = true;
  const nodes = element.childNodes;
  for (let i = 0, l = nodes.length; i < l; ++i) {
    if (nodes[i].nodeType === Node.ELEMENT_NODE) {
      leafElement = false;
      break;
    }
  }
  if (leafElement) {
    const value = styleObj.getPropertyValue('color');
    try {
      target['color'] = invertColor(value);
    } catch (e) {
      console.log(e);
    }
  }
}

function injectBackground(
  target: InlineStyles,
  styleObj: CSSStyleDeclaration,
  element: HTMLElement
) {
  if ('none' === styleObj.getPropertyValue('background-image')) {
    const value = styleObj.getPropertyValue('background-color');
    try {
      target['background'] = invertColor(value);
    } catch (e) {
      console.log(e);
    }
  }
}

// 写入元素的style属性中
function updateAttribute(element: HTMLElement, inlineStyles: InlineStyles) {
  const changedStyles = Object.keys(inlineStyles);
  if (!changedStyles.length) {
    return;
  }

  const changedStyleList = changedStyles.map(
    (prop) => `${prop}:${inlineStyles[prop]}`
  );

  const styleAttr = element.getAttribute('style');
  if (!styleAttr) {
    element.setAttribute('style', changedStyleList.join(';'));
    return;
  }

  element.setAttribute(
    'style',
    styleAttr
      .split(';')
      .filter((style) => !changedStyles.some((prop) => style.startsWith(prop)))
      .concat(changedStyleList)
      .join(';')
  );
}

export const harmlessPrograms = [injectColor];
export const effectivePrograms = [injectBackground, injectColor2];

export function changeNode(
  injectionPrograms: ((
    target: InlineStyles,
    styleObj: CSSStyleDeclaration,
    element: HTMLElement
  ) => void)[],
  element: HTMLElement
) {
  const computedStyles = window.getComputedStyle(element);
  if (!computedStyles) {
    console.log('non-styles', element);
    return;
  }

  const inlineStyles: InlineStyles = {};
  for (let i = 0; i < injectionPrograms.length; i++) {
    injectionPrograms[i](inlineStyles, computedStyles, element);
  }

  updateAttribute(element, inlineStyles);
}
